/**
*
*Daniel Ruslanov Filipov
*FN: 71373
*IS
*2012/2013
*VS2010 SP1
*
**/


#include "Expression.h"
#include <iostream>
#include "LinkedList.h"
#include <string>
#include <fstream>
#include <iomanip>
using namespace std;
static int colSize[1024];
void PutChar(char i,int *buffLen,char* buff)
{
	buff[*buffLen]=i;
	buff[*buffLen+1]='\0';
	*buffLen+=1;
}
template <class T>
int GetMaxCols(LinkedList<T> *pList, char* fileName,int& colMax)
{
	ifstream File;
	File.open(fileName, ios::in );
	if(!File)
	{
		cout<<"Couldn't open database file :"<<fileName<<endl;
		assert(false);
	}
	File.seekg(0, ios::end);
	if ((int)File.tellg() == 0)
	{
		cout<<"File empty! No records loaded!";
		assert(false);
	}
	else
	{
		File.seekg(0, ios::beg);
		bool isString=false;
		char i;
		int col=1;
		while (File.good())     // loop while extraction from file is possible
		{
			File.get(i);
			if(!File.eof())
			{
				switch(i)
				{
				case ',':
					if(!isString)
					{
						col++;
					}
					break;
				case'"':
					isString=!isString;
					break;
				case'\\':
					if(isString)
					{
						File.get(i);
					}
					break;
				case '\n':
					if(col>colMax) colMax=col;
					col=1;
					break;
				default:
					break;
				}
			}
			else
			{
				if(col>colMax) colMax=col;
			}
		}
	}
	for(int i=0;i<colMax;i++) colSize[i]=0;
	
	return colMax;
	File.close();
}
template <class T>
int FileOpen(LinkedList<T> *pList, char* fileName,int& colMax,int& widthMax)
{
	
	colMax=GetMaxCols(pList,fileName,colMax);
	ifstream File;
	File.open(fileName, ios::in );
	File.seekg(0, ios::beg);
	pList->RemoveAll();
	bool isString=false;
	char i;
	char buff[1024];
	int buffLen=0;
	int col=1;
	while (File.good())     // loop while extraction from file is possible
	{
		File.get(i);
		if(File.eof())
		{
			if(buff[0]=='\0') pList->AddTail("");
			else pList->AddTail(buff);
			if(buffLen>colSize[col]-1) colSize[col-1]=buffLen;
		}
		else
		{
			switch(i)
			{
			case ',':
				if(isString)
				{
					PutChar(i,&buffLen,buff);
				}
				else
				{
					if(buff[0]=='\0') pList->AddTail("");
					else pList->AddTail(buff);
					if(buffLen>colSize[col-1]) colSize[col-1]=buffLen;
					col++;
					buff[0]='\0';
					buffLen=0;
				}
				break;
			case'"':
				isString=!isString;
				break;
			case'\\':
				if(isString)
				{
					PutChar(i,&buffLen,buff);
					File.get(i);
					PutChar(i,&buffLen,buff);
				}
				else
				{
					PutChar(i,&buffLen,buff);
				}
				break;
			case '\n':
				if(buff[0]=='\0') pList->AddTail("");
				else pList->AddTail(buff);
				if(buffLen>colSize[col-1]) colSize[col-1]=buffLen;
				col++;
				buff[0]='\0';
				buffLen=0;
				while(col<=colMax)
				{
					pList->AddTail("");
					col++;
				}
				col=1;
				break;
			default:
				PutChar(i,&buffLen,buff);
				break;
			}
		}
		//pList->AddTail(buff);// get box from file
		//File.seekg(1, ios::cur);
		//if (File.good())
		//pList->AddTail(i);
	
	}
	File.close();
	return widthMax;
}
template <class T>
void FileSave(LinkedList<T> *pList, char* fileName,int& colMax)
{
	ofstream File;
	File.open(fileName, ios::out | ios::trunc);
	if(!File)
	{
		cout<<"Couldn't open database file :"<<fileName<<endl;	
	}
	// Save to file
	int col=0;
	for(Iterator<T> iterator = pList->GetIterator();
		! iterator.EndReached();
		iterator.MoveNext())
	{
		File << iterator.GetCurrent()<<",";
		col=(col+1)%colMax;
		if(col==(colMax-1)) File<<iterator.GetCurrent()<<endl;
	}
	//pList->toFile(File);
	File.close();
}
char* GetFileName(char* fileName)
{
	fstream File;
	File.open(fileName, ios::in | ios::out);
	if(!File)
	{
		cout<<"Couldn't open database file :"<<fileName<<endl;
		cout<<"Do you want to create a new file with this name y/n"<<endl;
		char c;
		cin>>c;
		if(c=='y'||c=='Y')
		{
			File.open(fileName, ios::binary | ios::out );
			
		}
	}
	File.close();
	return fileName;
}

void PrintMenu()
{
	cout<<"[1]Open"<<endl;
	cout<<"[2]Save"<<endl;
	cout<<"[3]Save as"<<endl;
	cout<<"[4]Print table"<<endl;
	cout<<"[5]Edit cell"<<endl;
	cout<<"[x]Exit"<<endl;
}
template <class T>
void PrintTable(LinkedList<T> *pList, int Start, int End,int& colMax,int& widthMax )
{
	int col=0;
	char* buff;
	for(Iterator<T> iterator = pList->GetIterator();
		! iterator.EndReached();
		iterator.MoveNext())
	{
		buff=new char[strlen(iterator.GetCurrent().c_str())+1];
		strcpy(buff,iterator.GetCurrent().c_str());
		if(buff[0]=='=')
		{
			buff[0]=' ';
			iterator.SetCurrentCalculate();
			Expression e(buff);
			e.GetExpression();
			e.GetNormalizedExpression();
			cout<< setw(colSize[col]);
			cout << e.GetValue()<<"|";
			//Calc box and print the result
		}
		else
		{
			cout<< setw(colSize[col]);
			cout << iterator.GetCurrent()<<"|";
		}
		col=(col+1)%colMax;
		if(col==0) cout<<endl;
	}
	cout << endl;
}
/*template <class T>
void FillList(LinkedList<T> *pList, int Start, int End)
{
	for(int i = Start; i <= End; i++)
	{
		pList->AddTail(i);
	}
	pList->AddTail(13.5);
	pList->AddTail("string");
}
*/
void main(int argc, char* argv[])
{
	//const int ELEM_COUNT = 10;
	fstream File;
	char* fileName=NULL;
	char choice=NULL;
	char buff[1024];
	LinkedList<string> newList;
	int colMax=0;
	int widthMax=0;
	int col=0;
	int row=0;
	if(argc==2) 
	{
		fileName = new char[strlen(argv[1])+1];
		strcpy(fileName,argv[1]);
		widthMax=FileOpen(&newList, fileName,colMax,widthMax);
	}
	else
	{
		cout<<"Please, Enter file name for the data:"<<endl;
		cin.get(buff,1024);
		fileName = new char[strlen(buff)+1];
		strcpy(fileName,buff);
		GetFileName(fileName);
		widthMax=FileOpen(&newList, fileName,colMax,widthMax);
	}
	//FillList(&newList, 0, 10);
	do
	{
		PrintMenu();
		
		cin>>choice;
		cin.ignore();
		switch(choice)
		{
		case '1'://open
			if(fileName) delete[] fileName;
			cout<<"Please, Enter file name for the data:"<<endl;
			cin.get(buff,1024);
			fileName = new char[strlen(buff)+1];
			strcpy(fileName,buff);
			GetFileName(fileName);
			widthMax=FileOpen(&newList, fileName,colMax,widthMax);
			break;
		case '2'://save
			if(fileName==NULL){cout<<"No file have been read. File name empty!";}
			else FileSave(&newList, fileName,colMax);
			break;
		case '3'://save as
			if(fileName) delete[] fileName;
			cout<<"Please, Enter file name for the data:"<<endl;
			cin.get(buff,1023);
			fileName = new char[strlen(buff)+1];
			strcpy(fileName,buff);
			
			File.open(fileName, ios::in | ios::out);
			if(File)
			{
				cout<<"File already exist!"<<endl;
				cout<<"Do you want to overwrite the file with this name y/n"<<endl;
				char c;
				cin>>c;
				File.close();
				if(c=='y'||c=='Y') FileSave(&newList,fileName,colMax);			
			}
			else FileSave(&newList,fileName,colMax);
			break;
		case '4'://print table
			
			PrintTable(&newList, 0, newList.GetCount() - 1,colMax,widthMax);
			break;
		case '5'://edit cell
			cout<<"Enter row number:";
			cin>>row;
			cout<<endl<<"Enter column number:";
			cin>>col;
			cout<<endl<<"Enter cell value:";
			buff[0]='\0';
			cin.ignore();
			cin.get(buff,1023);
			cin.clear();
			if(buff[0]!='\0')newList.SetAt(((row-1)*colMax)+col-1,buff);
			if(strlen(buff)>colSize[col-1]) colSize[col-1]=strlen(buff);
			break;
		case 'x':
			cout<<":(";
			break;
		default:
			break;
		}
	}while(choice!='x');
	/*FillList(&newList, 0, ELEM_COUNT - 1);

	int foo;
	
	std::cout << "Walking the list via index...";

	// try to walk the list via index
	for(int i = 0; i < ELEM_COUNT; i++)
	{
		foo = newList.GetAt(i);
	}

	std::cout << "done\n";
	
	cout << "Walking the list via iterator...";

	// try to walk the list via iterator
	for(Iterator<int> iterator = newList.GetIterator();
		! iterator.EndReached();
		iterator.MoveNext())
	{
		cout << iterator.GetCurrent();
	}

	cout << "done\n";
	*/
}


